package cn.angis.quartz.controller;

import cn.angis.common.annotation.SLog;
import cn.angis.common.constant.Constant;
import cn.angis.common.constant.DatePattern;
import cn.angis.common.model.R;
import cn.angis.common.util.StringU;
import cn.angis.db.controller.BaseController;
import cn.angis.db.model.PageModel;
import cn.angis.db.model.PageOfResult;
import cn.angis.quartz.dto.input.JobInput;
import cn.angis.quartz.dto.output.JobOutput;
import cn.angis.quartz.dtomapper.JobStruct;
import cn.angis.quartz.model.SysJob;
import cn.angis.quartz.service.JobService;
import cn.angis.quartz.util.CronUtils;
import cn.angis.quartz.util.ScheduleUtils;
import com.alibaba.excel.EasyExcel;
import org.noear.snack.core.utils.DateUtil;
import org.noear.solon.annotation.Controller;
import org.noear.solon.annotation.Get;
import org.noear.solon.annotation.Mapping;
import org.noear.solon.annotation.Post;
import org.noear.solon.core.handle.DownloadedFile;
import org.noear.solon.validation.annotation.NotBlank;
import org.noear.solon.validation.annotation.NotEmpty;
import org.noear.solon.validation.annotation.Validated;
import org.quartz.SchedulerException;

import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.util.List;

/**
 * 定时任务调度表前端控制器
 *
 * @author angis.cn
 * @Date 2025-06-04
 */
@SLog("定时任务调度表")
@Mapping("/quartz/job/")
@Controller
public class JobController extends BaseController<JobService, SysJob> {

    /**
     * 分页查询
     *
     * @param jobInput
     * @param pageModel
     * @return R<PageOfResult < JobOutput>>
     * @Date 2025-06-04
     */
    @SLog
    @Get
    @Mapping("page")
    public R<PageOfResult<SysJob>> page(JobInput jobInput, PageModel pageModel) {
        return success(pageListByEntity(jobInput, pageModel));
    }

    @Mapping("export")
    @Post
    public DownloadedFile export(JobInput jobInput) throws IOException {
        List<JobOutput> list = baseService.list(jobInput);
        File file = newFile( DateUtil.format(new Date(), DatePattern.PURE_DATETIME_MS_PATTERN) + ".xlsx");
        EasyExcel.write(file, JobOutput.class).sheet("定时任务").doWrite(list);

        return new DownloadedFile(file, "定时任务" + DateUtil.format(new Date(), DatePattern.PURE_DATETIME_PATTERN) + ".xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
    }

    @Mapping("{id}")
    @Get
    public R<JobOutput> get(String id) {
        JobOutput jobOutput = JobStruct.INSTANCE.toOutput(getById(id));
        return success(jobOutput);
    }

    /**
     * 保存
     *
     * @param jobInput
     * @return R<Boolean>
     * @Date 2025-06-04
     */
    @SLog
    @Post
    @Mapping("save")
    public R<Boolean> save(@Validated JobInput jobInput) {
        SysJob job = JobStruct.INSTANCE.toJob(jobInput);
        if (!CronUtils.isValid(job.getCronExpression())) {
            return error("新增任务'" + job.getName() + "'失败，Cron表达式不正确");
        } else if (StringU.containsIgnoreCase(job.getInvokeTarget(), Constant.LOOKUP_RMI)) {
            return error("新增任务'" + job.getName() + "'失败，目标字符串不允许'rmi'调用");
        } else if (StringU.containsAnyIgnoreCase(job.getInvokeTarget(), new String[]{Constant.LOOKUP_LDAP, Constant.LOOKUP_LDAPS})) {
            return error("新增任务'" + job.getName() + "'失败，目标字符串不允许'ldap(s)'调用");
        } else if (StringU.containsAnyIgnoreCase(job.getInvokeTarget(), new String[]{Constant.HTTP, Constant.HTTPS})) {
            return error("新增任务'" + job.getName() + "'失败，目标字符串不允许'http(s)'调用");
        } else if (StringU.containsAnyIgnoreCase(job.getInvokeTarget(), Constant.JOB_ERROR_STR)) {
            return error("新增任务'" + job.getName() + "'失败，目标字符串存在违规");
        } else if (!ScheduleUtils.whiteList(job.getInvokeTarget())) {
            return error("新增任务'" + job.getName() + "'失败，目标字符串不在白名单内");
        }
        return super.save(job);
    }

    /**
     * 修改
     *
     * @param jobInput
     * @return R<Boolean>
     * @Date 2025-06-04
     */
    @SLog
    @Post
    @Mapping("update")
    public R<Boolean> update(@Validated JobInput jobInput) {
        SysJob job = JobStruct.INSTANCE.toJob(jobInput);
        if (!CronUtils.isValid(job.getCronExpression())) {
            return error("修改任务'" + job.getName() + "'失败，Cron表达式不正确");
        } else if (StringU.containsIgnoreCase(job.getInvokeTarget(), Constant.LOOKUP_RMI)) {
            return error("修改任务'" + job.getName() + "'失败，目标字符串不允许'rmi'调用");
        } else if (StringU.containsAnyIgnoreCase(job.getInvokeTarget(), new String[]{Constant.LOOKUP_LDAP, Constant.LOOKUP_LDAPS})) {
            return error("修改任务'" + job.getName() + "'失败，目标字符串不允许'ldap(s)'调用");
        } else if (StringU.containsAnyIgnoreCase(job.getInvokeTarget(), new String[]{Constant.HTTP, Constant.HTTPS})) {
            return error("修改任务'" + job.getName() + "'失败，目标字符串不允许'http(s)'调用");
        } else if (StringU.containsAnyIgnoreCase(job.getInvokeTarget(), Constant.JOB_ERROR_STR)) {
            return error("修改任务'" + job.getName() + "'失败，目标字符串存在违规");
        } else if (!ScheduleUtils.whiteList(job.getInvokeTarget())) {
            return error("修改任务'" + job.getName() + "'失败，目标字符串不在白名单内");
        }
        return super.update(job);
    }

    @Mapping("changeStatus")
    @Post
    public R<Integer> changeStatus(JobInput jobInput) throws SchedulerException {
        return success(baseService.changeStatus(jobInput));
    }

    @Mapping("run")
    @Post
    public R<String> run(String id) throws SchedulerException {
        boolean result = baseService.run(id);
        return result ? success() : error("任务不存在或已过期！");
    }

    /**
     * 删除
     *
     * @param id
     * @return R<Boolean>
     * @Date 2025-06-04
     */
    @SLog
    @Post
    @Mapping("delete")
    public R<Boolean> delete(@NotBlank String id) {
        return super.delete(id);
    }

    /**
     * 批量删除
     *
     * @param ids
     * @return R<Boolean>
     * @Date 2025-06-04
     */
    @SLog
    @Post
    @Mapping("deleteBatch")
    public R<Boolean> deleteBatch(@NotEmpty List<String> ids) {
        return super.deleteBatch(ids);
    }
}
